package org.clockworkmages.games.anno1186.model.option;

import java.util.List;

import javax.xml.bind.annotation.XmlAttribute;

import org.clockworkmages.games.anno1186.GameBeansContext;
import org.clockworkmages.games.anno1186.GameDataService;
import org.clockworkmages.games.anno1186.GameGuiService;
import org.clockworkmages.games.anno1186.GameState;
import org.clockworkmages.games.anno1186.GameStateService;
import org.clockworkmages.games.anno1186.GameTimeService;
import org.clockworkmages.games.anno1186.SituationPoolService;
import org.clockworkmages.games.anno1186.SituationService;
import org.clockworkmages.games.anno1186.dao.ImageIconDescriptor;
import org.clockworkmages.games.anno1186.model.GameObject;
import org.clockworkmages.games.anno1186.model.character.NonPlayerCharacter;
import org.clockworkmages.games.anno1186.model.situation.Situation;
import org.clockworkmages.games.anno1186.situations.combat.CombatSituation;
import org.clockworkmages.games.anno1186.text.TextUtil;

/**
 * @author Tomek
 * 
 */
public abstract class Option
		extends GameObject {

	private String label;

	private String tooltip;

	/**
	 * Text to be presented after the option has been selected. Can be null,
	 * especially if the option targets a Situation or Location that have their
	 * own description.
	 */
	private String textAfter;

	private boolean consumesCombatAction;

	private boolean textfield = false;

	private String condition;

	/**
	 * Special condition that indicates that this option shall only be available
	 * for evaluation if the previous option was evaluated as false.
	 */
	private boolean or;

	private long timePassed;

	/**
	 * Id of the icon defined in game data as ${link {@link ImageIconDescriptor}
	 * . If defined, the appropriate icon will be displayed before the option's
	 * label.
	 */
	private String icon;

	/**
	 * ID of the situation that this option will take the player to.
	 */
	private String goToSituation;

	/**
	 * ID of the situation pool that this option will take the player to.
	 * 
	 * Situation pool will then return a single situation - either selected
	 * randomly or based on logical conditions.
	 */
	private String goToSituationPool;

	/**
	 * Id of the enemy.
	 */
	private String goToCombat;

	/**
	 * If sets to <b>true</b> the new situation will be added to the situation
	 * stack and it will be possible to return from it to the current situation.
	 * 
	 * Typical applications are opening an inventory or a spellbook when in a
	 * camp or in combat; examining an enemy or item; or going to a shop while
	 * in on the city screen.
	 */
	private boolean addToStack = false;

	/**
	 * If sets to <b>true</b> selecting this option will remove current
	 * situation from stack, returning the player to the previous situation on
	 * stack.
	 */
	private boolean goBack = false;

	public Option() {

	}

	public Option(String id) {
		super(id);
	}

	public void select() {

		GameTimeService gameTimeService = GameBeansContext
				.getBean(GameTimeService.class);
		SituationService situationManager = GameBeansContext
				.getBean(SituationService.class);
		GameGuiService gameGuiService = GameBeansContext
				.getBean(GameGuiService.class);
		GameDataService gameDataService = GameBeansContext
				.getBean(GameDataService.class);
		GameStateService gameStateService = GameBeansContext
				.getBean(GameStateService.class);
		GameState gameState = gameStateService.getGameState();

		gameState.setPreviousSituation(gameState.getCurrentSituation());

		if (this.consumesCombatAction && gameStateService.isInCombat()) {
			// the player has used some item or has cast a spell in the middle
			// of combat, consuming his combat turn.
			// Return to combat situation screen immediately:
			List<Situation> situationStack = gameState.getSituationStack();
			int size = situationStack.size();
			for (int i = size - 1; i >= 0; i--) {
				if (situationStack.get(i) instanceof CombatSituation) {
					((CombatSituation) situationStack.get(i))
							.setPlayerConsumedCombatAction(true);
					break;
				} else {
					situationStack.remove(i);
				}
			}
		} else if (goBack) {
			gameStateService.removeCurrentSituation();
		} else if (this.goToSituation != null) {
			if (!this.addToStack) {
				gameStateService.removeCurrentSituation();
			}
			for (String s : this.goToSituation.split(",")) {
				// in some cases the "gotToSituation" can contain a
				// coma-separated list of situations that should all be added to
				// the situation stack in the specified order
				String situationId = s.trim();
				gameStateService.addSituation(situationId, true);
			}
		} else if (this.goToSituationPool != null) {
			SituationPoolService situationPoolService = GameBeansContext
					.getBean(SituationPoolService.class);
			Situation situationFromPool = situationPoolService
					.getRandomSituationFromPool(this.goToSituationPool);
			gameStateService.addSituation(situationFromPool, this.addToStack);
		} else if (this.goToCombat != null) {
			NonPlayerCharacter enemy = gameDataService.getGameData().getNpcs()
					.get(this.goToCombat);
			CombatSituation combatSituation = new CombatSituation(enemy);
			gameStateService.addSituation(combatSituation, this.addToStack);
		}

		if (timePassed > 0) {
			gameTimeService.advanceTime(timePassed);
		}

		if (textAfter != null) {
			gameGuiService.getTextPane().removeTrailing("[...]");
			String parsedText = TextUtil.parse(this.textAfter);
			gameGuiService.getTextPane().appendText(parsedText + "\n");
		}

		situationManager.playCurrentSituation();
	}

	@XmlAttribute
	public String getLabel() {
		return label;
	}

	public String getTooltip() {
		return tooltip;
	}

	@XmlAttribute
	public boolean isConsumesCombatAction() {
		return consumesCombatAction;
	}

	public String getTextAfter() {
		return textAfter;
	}

	public void setTextAfter(String text) {
		this.textAfter = text;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	public void setTooltip(String description) {
		this.tooltip = description;
	}

	public void setConsumesCombatAction(boolean consumesCombatAction) {
		this.consumesCombatAction = consumesCombatAction;
	}

	@XmlAttribute
	public boolean isTextfield() {
		return textfield;
	}

	public void setTextfield(boolean textfield) {
		this.textfield = textfield;
	}

	public String getCondition() {
		return condition;
	}

	public void setCondition(String condition) {
		this.condition = condition;
	}

	@XmlAttribute
	public boolean isOr() {
		return or;
	}

	public void setOr(boolean or) {
		this.or = or;
	}

	@XmlAttribute
	public long getTimePassed() {
		return timePassed;
	}

	public void setTimePassed(long timePassed) {
		this.timePassed = timePassed;
	}

	@XmlAttribute
	public String getIcon() {
		return icon;
	}

	public void setIcon(String icon) {
		this.icon = icon;
	}

	@XmlAttribute
	public String getGoToSituation() {
		return goToSituation;
	}

	public void setGoToSituation(String goToSituation) {
		this.goToSituation = goToSituation;
	}

	@XmlAttribute
	public String getGoToSituationPool() {
		return goToSituationPool;
	}

	public void setGoToSituationPool(String goToSituationPool) {
		this.goToSituationPool = goToSituationPool;
	}

	@XmlAttribute
	public boolean isAddToStack() {
		return addToStack;
	}

	public void setAddToStack(boolean addToStack) {
		this.addToStack = addToStack;
	}

	@XmlAttribute
	public boolean isGoBack() {
		return goBack;
	}

	public void setGoBack(boolean goBack) {
		this.goBack = goBack;
	}

	@XmlAttribute
	public String getGoToCombat() {
		return goToCombat;
	}

	public void setGoToCombat(String goToCombat) {
		this.goToCombat = goToCombat;
	}

}
